package com.lagou.handler;

import com.lagou.pojo.RpcRequest;
import com.lagou.service.UserServiceImpl;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.concurrent.EventExecutorGroup;
import org.reflections.Reflections;

import java.lang.reflect.Method;
import java.util.Set;

/**
 * 自定义的业务处理器
 */
public class UserServiceHandler extends ChannelInboundHandlerAdapter {

    //当客户端读取数据时,该方法会被调用
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

//        //注意:  客户端将来发送请求的时候会传递一个参数:  UserService#sayHello#are you ok
//         //1.判断当前的请求是否符合规则
//        if(msg.toString().startsWith("UserService")){
//            //2.如果符合规则,调用实现类货到一个result
//            UserServiceImpl service = new UserServiceImpl();
//            String result = service.sayHello(msg.toString().substring(msg.toString().lastIndexOf("#")+1));
//            //3.把调用实现类的方法获得的结果写到客户端
//            ctx.writeAndFlush(result);
//        }

        // 把客户端发送的数据强转成RpcRequest
        RpcRequest rpcRequest = (RpcRequest) msg;
        // 获取接口实现类并执行方法
        Object invoke = handler(rpcRequest);
        // 把调用方法的结果封装成RpcRequest刷新到远程的客户端节点
        RpcRequest request = new RpcRequest();
        request.setParameters(new String[]{(String)invoke});
        ctx.writeAndFlush(request);

    }

    private Object handler(RpcRequest rpcRequest) throws Exception {
        // 判断是否符合约定，符合则调用本地方法，返回数据
        // 得到接口的实现类的名字
        String className = getImplClassName(rpcRequest);
        // 得到实现类的class对象
        Class<?> clazz = Class.forName(className);
        // 得到实现类的实例对象
        Object instance = clazz.newInstance();
        // 得到客户端要调用的方法
        Method method = clazz.getMethod(rpcRequest.getMethodName(), rpcRequest.getParameterTypes());
        // 通过反射调用实现类的方法
        return method.invoke(instance, rpcRequest.getParameters());
    }

    private String getImplClassName(RpcRequest rpcRequest) throws Exception {
        //服务方接口和实现类所在的包路径
        String interfacePath = "com.lagou.service";
        int lastDot = rpcRequest.getClassName().lastIndexOf(".");
        String interfaceName = rpcRequest.getClassName().substring(lastDot);
        Class superClass = Class.forName(interfacePath + interfaceName);
        Reflections reflections = new Reflections(interfacePath);
        //得到某接口下的所有实现类
        Set<Class> implClassSet = reflections.getSubTypesOf(superClass);
        //说明没有实现类
        if (implClassSet.size() == 0) {
            System.out.println("未找到实现类");
            return null;
        } else if (implClassSet.size() > 1) {
            System.out.println("找了多个实现类，未明确使用哪一个");
            return null;
        } else {
            //把实现类的集合转换成数组
            Class[] classes = implClassSet.toArray(new Class[0]);
            //返回实现类的名字
            return classes[0].getName();
        }
    }

}
